/*
 *
 *   Copyright (C) 2005 by Raymond Huang
 *   plushuang at users.sourceforge.net
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *  ---
 *
 *  In addition, as a special exception, the copyright holders give
 *  permission to link the code of portions of this program with the
 *  OpenSSL library under certain conditions as described in each
 *  individual source file, and distribute linked combinations
 *  including the two.
 *  You must obey the GNU Lesser General Public License in all respects
 *  for all of the code used other than OpenSSL.  If you modify
 *  file(s) with this exception, you may extend this exception to your
 *  version of the file(s), but you are not obligated to do so.  If you
 *  do not wish to do so, delete this exception statement from your
 *  version.  If you delete this exception statement from all source
 *  files in the program, then also delete it here.
 *
 */

#ifndef __DOWNLOAD_NODE_H
#define __DOWNLOAD_NODE_H

#include <urlglib/proxy_node.h>

#ifdef __cplusplus
extern "C" {
#endif

#define DOWNLOAD_NODE(obj)           ((DownloadNode*)(obj))
#define DOWNLOAD_NODE_TAG            "download_setting"

typedef struct _DownloadNode         DownloadNode;

struct _DownloadNode {
	BASE_NODE_FIELDS;

	// control data ------------------------------
	GStaticRecMutex     mutex;
	gpointer            thread;    // point to DownloadTask
	guint               sync_code;
	int                 proxy_mode;
	int                 proxy_nth;
	// download_node_pick_proxy () return the nth proxy. (then proxy_nth++)
	// For example : 
	// if (proxy_nth == 2),
	//     download_node_pick_proxy () return the 2th proxy. (then set proxy_nth = 3)

	// base data ---------------------------------
	int   state;
	char* url;
	char* directory;
	char* filename;
	char* referer;

	// login
	unsigned int  login;    // TRUE or FALSE
	char* username;
	char* password;

	unsigned int  start_mode;
	unsigned int  split_max;

	unsigned int  redirect_max;
	unsigned int  retry_max;
	unsigned int  retry_delay;

	// infomation while downloading --------------
	unsigned int  redirect_times;
	unsigned int  retry_times;

	gboolean   resumable;
	gdouble    completed_size;     // completed size
	gdouble    total_size;         // total size
	gdouble    percent;       // completed percent
	gdouble    speed;         // download speed
	gchar*     message;       // error message
};

typedef enum {
	DOWNLOAD_APPLY_LOGIN = 1 << 0,
	DOWNLOAD_APPLY_PROXY = 1 << 1,
	DOWNLOAD_APPLY_REFERER = 1 << 2,
	DOWNLOAD_APPLY_ALL   = DOWNLOAD_APPLY_LOGIN | DOWNLOAD_APPLY_PROXY | DOWNLOAD_APPLY_REFERER
} DownloadApplyFlag;

typedef enum {
	DOWNLOAD_PROXY_NONE,      // Direct connect
	DOWNLOAD_PROXY_FIRST,     // First only
	DOWNLOAD_PROXY_TRY_ALL    // Try all proxy if download fail.
} DownloadNodeProxyMode;

typedef enum {
	DOWNLOAD_STATE_WAITING,
	DOWNLOAD_STATE_STOP,
	DOWNLOAD_STATE_SCHEDULE,

	DOWNLOAD_STATE_RETRY,
	DOWNLOAD_STATE_ACTIVE,

	DOWNLOAD_STATE_COMPLETED,
	DOWNLOAD_STATE_DELETED,
	DOWNLOAD_STATE_ERROR
} DownloadNodeState;

// when status equ DOWNLOAD_STATE_WAITING ,DOWNLOAD_STATE_STOP ,or DOWNLOAD_STATE_SCHEDULE,
// change start_mode will affect status.
typedef enum {
	DOWNLOAD_START_AUTO,
	DOWNLOAD_START_MANUAL,
	DOWNLOAD_START_SCHEDULE
} DownloadNodeStartMode;

DownloadNode* download_node_new ();

#define download_node_ref(obj)      base_node_ref(BASE_NODE(obj));
#define download_node_unref(obj)    base_node_unref(BASE_NODE(obj));

#define download_node_lock(obj)     g_static_rec_mutex_lock(&(obj)->mutex)
#define download_node_unlock(obj)   g_static_rec_mutex_unlock(&(obj)->mutex)

#define download_node_next(o)       (DownloadNode*)base_node_next(BASE_NODE(o))
#define download_node_prev(o)       (DownloadNode*)base_node_prev(BASE_NODE(o))
#define download_node_unlink(o)     base_node_unlink (BASE_NODE (o))

#define download_node_first_proxy(o)   (ProxyNode*)base_node_first_child (BASE_NODE (o))
#define download_node_last_proxy(o)    (ProxyNode*)base_node_last_child (BASE_NODE (o))
#define download_node_nth_proxy(o,n)   (ProxyNode*)base_node_nth_child (BASE_NODE (o),n)
#define download_node_n_proxy(o)       base_node_n_children (BASE_NODE (o))

#define download_node_modified(o)   ((o)->sync_code++)
#define download_node_is_active(o)  ( ((o)->thread) ? TRUE : FALSE )

// DownloadNodeProxyMode download_node_get_proxy_mode (DownloadNode* dnode);
// void download_node_set_proxy_mode (DownloadNode* dnode, DownloadNodeProxyMode);
#define download_node_get_proxy_mode(o)      ((o)->proxy_mode)
#define download_node_set_proxy_mode(o,m)    ((o)->proxy_mode = m)

void download_node_prepend_proxy (DownloadNode* dnode, ProxyNode* pnode);
void download_node_append_proxy (DownloadNode* dnode, ProxyNode* pnode);
void download_node_remove_proxy (DownloadNode* dnode, ProxyNode* pnode);
void download_node_insert_before (DownloadNode* parent, ProxyNode* sibling, ProxyNode* node);
void download_node_insert_after (DownloadNode* parent, ProxyNode* sibling, ProxyNode* node);

// Pick the next ProxyNode store in DownloadNode.
// If no ProxyNode started, pick the first ProxyNode store in DownloadNode
// @return NULL if no proxy
ProxyNode* download_node_pick_proxy (DownloadNode* dnode);

void download_node_set_start_mode (DownloadNode* dnode, DownloadNodeStartMode m);

// If they are NULL, this function may affect filename, login, username, password
void download_node_set_url (DownloadNode* dnode, const char* url);
void download_node_set_directory (DownloadNode* dnode, const char* d);
void download_node_set_filename (DownloadNode* dnode, const char* f);
void download_node_set_referer (DownloadNode* dnode, const char* r);
void download_node_set_username (DownloadNode* dnode, const char* u);
void download_node_set_password (DownloadNode* dnode, const char* p);
void download_node_set_message (DownloadNode* dnode, const char* m);
void download_node_apply (DownloadNode* dest, DownloadNode* src, DownloadApplyFlag flag);
void download_node_assign (DownloadNode* dest, DownloadNode* src);
void download_node_assign_proxy (DownloadNode* dest, DownloadNode* src);

int  download_node_start (DownloadNode* dnode);
void download_node_stop  (DownloadNode* dnode);

// config writer & parser --------------------------------------------
void download_node_write_conf (DownloadNode* dnode, ConfWriter* cw);
void download_node_parser_attr (const gchar**     attr_names,
                                const gchar**     attr_values,
                                DownloadNode*     dnode);

extern const GMarkupParser download_node_parser;

#ifdef __cplusplus
}
#endif

#endif  // End of __DOWNLOAD_NODE_H


